﻿#ifndef __ROAD_LINE_UTILS_H__
#define __ROAD_LINE_UTILS_H__

#include <cmath>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

// #ifndef STB_IMAGE_WRITE_IMPLEMENTATION
// #define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
// #endif

class RoadLineUtils
{
    static const int s_white_color = 1;  // 路面颜色
    static const int s_black_color = 0;  // 路面边缘线颜色
    static const int s_other_color = -1; // 其他颜色
    static const int s_red_color   = 2;  // 路标颜色
    static const int s_fill_color  = -2; // 填充颜色 算法更改的颜色

    static const int s_image_width  = 320;
    static const int s_image_height = 240;

public:
    static int GetImageWidth() { return s_image_width; }
    static int GetImageHeight() { return s_image_height; }
    static int GetNetWidth() { return s_image_width * GetNetImageScale(); }
    static int GetNetHeight() { return s_image_height * GetNetImageScale(); }
    static float GetNetImageScale() { return 0.4f; }; // 128 * 96

    static std::string GetColorsText(int *colors, int max_width, int max_height)
    {
        std::ostringstream oss;
        for (int y = 0; y < max_height; y++)
        {
            for (int x = 0; x < max_width; x++)
            {
                int index = y * max_width + x;
                oss << colors[index] << " ";
            }
            oss << std::endl;
        }
        return oss.str();
    }

    // 修复路线颜色
    static std::string FixedRoadLineColors(int *colors, int max_width, int max_height)
    {
        static std::string s_forbid_forward = reinterpret_cast<const char *>(u8R"(禁止通行)");
        static std::string s_forward        = reinterpret_cast<const char *>(u8R"(直行)");
        static std::string s_turn_left      = reinterpret_cast<const char *>(u8R"(左转)");
        static std::string s_turn_right     = reinterpret_cast<const char *>(u8R"(右转)");

        auto center_x = max_width / 2;
        auto center_y = max_height / 2;
        // 24/ 6 = 4; 去底部4行 计算白色中心点的位置
        auto width                                        = max_width;
        auto height                                       = max_height / 6;
        auto offset_x                                     = 0;
        auto offset_y                                     = max_height - height;
        auto min_y                                        = offset_y;
        auto max_y                                        = max_height - 1;
        auto [white_color_center_x, white_color_center_y] = GetColorCenter(colors, s_white_color, offset_x, offset_y, width, height, max_width, max_height);
        // 黑色点超过一半
        // if (GetColorCount(colors, s_black_color, offset_x, offset_y, width, height, max_width, max_height) > (width * height / 3)) return s_forbid_forward;

        // 如果白色中心点为空, 则填充
        if (white_color_center_x < 0 || white_color_center_y < 0)
        {
            FillColors(colors, s_fill_color, offset_x, offset_y, width, height, max_width, max_height);
            return s_forbid_forward;
        }

        // 检测横向黑线
        auto line_height = 2;
        for (int y = max_height * 2 / 3; y <= (max_height - line_height); y++)
        {
            auto black_color_count = GetColorCount(colors, s_black_color, offset_x, y, width, line_height, max_width, max_height);
            if (black_color_count > (width * line_height * 0.8)) return s_forbid_forward;
        }

        auto black_color_center_x = 0;
        auto black_color_center_y = 0;

        // 以白色中心点为边界计算黑色中心点
        if (white_color_center_x < center_x)
        {
            // 路面在左, 路线在右
            auto black_color_count = GetColorCount(colors, s_black_color, white_color_center_x, offset_y, width - white_color_center_x, height, max_width, max_height);
            if (black_color_count < (height * height)) return s_forward;
            auto paris           = GetColorCenter(colors, s_black_color, white_color_center_x, offset_y, width - white_color_center_x, height, max_width, max_height);
            black_color_center_x = std::lround(paris.first);
            black_color_center_y = std::lround(paris.second);
        }
        else
        {
            // 路面在右, 路线在左
            auto black_color_count = GetColorCount(colors, s_black_color, offset_x, offset_y, white_color_center_x - offset_x, height, max_width, max_height);
            if (black_color_count < (height * height)) return s_forward;
            auto paris           = GetColorCenter(colors, s_black_color, offset_x, offset_y, white_color_center_x - offset_x, height, max_width, max_height);
            black_color_center_x = std::lround(paris.first);
            black_color_center_y = std::lround(paris.second);
        }

        // 不存在黑色中心点
        if (black_color_center_x < 0 && black_color_center_y < 0)
        {
            FillColors(colors, s_white_color, offset_x, offset_y, width, height, max_width, max_height);
            return s_forward;
        }

        // 如果中心点附近颜色过少, 则表明点在两端, 则填充白色 直行
        auto size                     = 4;
        auto center_black_color_count = GetColorCount(colors, s_black_color, black_color_center_x - size / 2, black_color_center_y - size / 2, size, size, max_width, max_height);
        if (center_black_color_count < (size * size) / 4 || black_color_center_x <= (max_width / 8) || black_color_center_x >= (max_width * 7 / 8))
        {
            FillColors(colors, s_white_color, offset_x, offset_y, width, height, max_width, max_height);
            return s_forward;
        }

        // 白色中心小于黑色中心
        if (white_color_center_x < black_color_center_x || black_color_center_x > center_x)
        {
            auto [min_x, max_x]                     = FindMinMaxX(colors, s_black_color, white_color_center_x, offset_y, width - white_color_center_x, height, max_width, max_height);
            auto [max_slope_min_x, max_slope_max_x] = GetMaxSlopeBothEndPointX(colors, s_black_color, min_x, max_x, min_y, max_y, max_width, max_height);
            if ((max_slope_min_x - max_slope_max_x) > 1) return s_turn_right;
        }

        if (white_color_center_x > black_color_center_x || black_color_center_x < center_x)
        {
            auto [min_x, max_x]                     = FindMinMaxX(colors, s_black_color, offset_x, offset_y, white_color_center_x - offset_x, height, max_width, max_height);
            auto [max_slope_min_x, max_slope_max_x] = GetMaxSlopeBothEndPointX(colors, s_black_color, min_x, max_x, min_y, max_y, max_width, max_height);
            if ((max_slope_max_x - max_slope_min_x) > 1) return s_turn_left;
        }

        // 修复水平方向的白点
        auto step = white_color_center_x > black_color_center_x ? -1 : 1;
        for (int y = offset_y; y < max_height; y++)
        {
            // 找该行离中心点最近黑点
            int black_color_x         = FindNearestX(colors, s_black_color, black_color_center_x, y, max_width, max_height);
            int black_color_min_x     = black_color_x < 0 ? 0 : black_color_x;
            int black_color_max_x     = black_color_x < 0 ? (max_width - 1) : black_color_x;
            int black_color_count     = 0;
            int black_color_max_count = max_width / 3;
            if (black_color_center_x < white_color_center_x)
            {
                // 线在左边优先取右边黑点靠近白中心的
                black_color_max_x = FindMaxX(colors, s_black_color, black_color_max_x, y, max_width, max_height, &black_color_count, black_color_max_count);
                black_color_min_x = FindMinX(colors, s_black_color, black_color_min_x, y, max_width, max_height, &black_color_count, black_color_max_count);
                // 剩余左边的点填充颜色
                if (black_color_min_x >= 0) FillColors(colors, s_fill_color, 0, y, black_color_min_x, 1, max_width, max_height);
                // 填充黑白中心点间的点为白点
                if (black_color_max_x >= 0) FillColors(colors, s_white_color, black_color_max_x + 1, y, white_color_center_x - black_color_max_x, 1, max_width, max_height);
            }
            else
            {
                // 线在右边优先取左边黑点靠近白中心的
                black_color_min_x = FindMinX(colors, s_black_color, black_color_min_x, y, max_width, max_height, &black_color_count, black_color_max_count);
                black_color_max_x = FindMaxX(colors, s_black_color, black_color_max_x, y, max_width, max_height, &black_color_count, black_color_max_count);
                // 剩余右边的点填充颜色
                if (black_color_max_x >= 0) FillColors(colors, s_fill_color, black_color_max_x + 1, y, max_width - black_color_max_x - 1, 1, max_width, max_height);
                // 填充黑白中心点间的点为白点
                if (black_color_min_x >= 0) FillColors(colors, s_white_color, white_color_center_x, y, black_color_min_x - white_color_center_x, 1, max_width, max_height);
            }
        }

        auto white_offset = std::abs(white_color_center_x - center_x);
        if (white_offset < 2) return s_forward;
        return white_color_center_x < center_x ? s_turn_left : s_turn_right;
    }

    // 获取两端X坐标
    static std::pair<int, int> GetMaxSlopeBothEndPointX(int *colors, int color, int min_x, int max_x, int min_y, int max_y, int max_width, int max_height)
    {
        auto min_min_y = min_y;
        auto min_max_y = max_y;
        auto min_min_x = FindMinX(colors, s_black_color, max_x, min_min_y, max_width, max_height, nullptr, max_width);
        while (min_min_x < 0 && min_min_y <= min_max_y)
        {
            min_min_y++;
            min_min_x = FindMinX(colors, s_black_color, max_x, min_min_y, max_width, max_height, nullptr, max_width);
        }
        auto min_max_x = FindMinX(colors, s_black_color, max_x, min_max_y, max_width, max_height, nullptr, max_width);
        while (min_max_x < 0 && min_min_y <= min_max_y)
        {
            min_max_y--;
            min_max_x = FindMinX(colors, s_black_color, max_x, min_max_y, max_width, max_height, nullptr, max_width);
        }
        auto max_min_y = min_y;
        auto max_max_y = max_y;
        auto max_min_x = FindMaxX(colors, s_black_color, min_x, max_min_y, max_width, max_height, nullptr, max_width);
        while (max_min_x < 0 && max_min_y <= max_max_y)
        {
            max_min_y++;
            max_min_x = FindMaxX(colors, s_black_color, min_x, max_min_y, max_width, max_height, nullptr, max_width);
        }
        auto max_max_x = FindMaxX(colors, s_black_color, min_x, max_max_y, max_width, max_height, nullptr, max_width);
        while (max_max_x < 0 && max_min_y <= max_max_y)
        {
            max_max_y--;
            max_max_x = FindMaxX(colors, s_black_color, min_x, max_max_y, max_width, max_height, nullptr, max_width);
        }
        auto min_abs = min_min_x < min_max_x ? (min_max_x - min_min_x) : (min_min_x - min_max_x);
        auto max_abs = max_min_x < max_max_x ? (max_max_x - max_min_x) : (max_min_x - max_max_x);
        return min_abs < max_abs ? std::make_pair(max_min_x, max_max_x) : std::make_pair(min_min_x, min_max_x);
    }

    // 获取靠近X的两端点
    static std::pair<int, int> GetNearBothEndPointX(int *colors, int color, int x, int min_y, int max_y, int max_width, int max_height)
    {
        auto min_x = FindMinX(colors, s_black_color, x, min_y, max_width, max_height, nullptr, max_width);
        auto max_x = FindMinX(colors, s_black_color, x, max_y, max_width, max_height, nullptr, max_width);
        return std::make_pair(min_x, max_x);
    }

    // 获取远离X的两端点
    static std::pair<int, int> GetFarBothEndPointX(int *colors, int color, int x, int min_y, int max_y, int max_width, int max_height)
    {
        auto min_x = FindMaxX(colors, s_black_color, x, min_y, max_width, max_height, nullptr, max_width);
        auto max_x = FindMaxX(colors, s_black_color, x, max_y, max_width, max_height, nullptr, max_width);
        return std::make_pair(min_x, max_x);
    }

    // 找指定颜色在指定区域的最小X
    static int FindMinX(int *colors, int color, int x, int y, int width, int height, int max_width, int max_height)
    {
        int min_x = -1;
        for (int i = 0; i < height; i++)
        {
            int iy = i + y;
            if (iy < 0 || iy >= max_height) continue;
            for (int j = 0; j < width; j++)
            {
                int jx = j + x;
                if (jx < 0 || jx >= max_width) continue;
                int index = iy * max_width + jx;
                if (colors[index] == color)
                {
                    if (min_x < 0 || jx < min_x)
                    {
                        min_x = jx;
                    }
                }
            }
        }
        return min_x;
    }

    // 找指定颜色在指定区域的最大X
    static int FindMaxX(int *colors, int color, int x, int y, int width, int height, int max_width, int max_height)
    {
        int max_x = -1;
        for (int i = 0; i < height; i++)
        {
            int iy = i + y;
            if (iy < 0 || iy >= max_height) continue;
            for (int j = 0; j < width; j++)
            {
                int jx = j + x;
                if (jx < 0 || jx >= max_width) continue;
                int index = iy * max_width + jx;
                if (colors[index] == color)
                {
                    if (max_x < 0 || jx > max_x)
                    {
                        max_x = jx;
                    }
                }
            }
        }
        return max_x;
    }

    // 找指定颜色在指定区域的最大X
    static std::pair<int, int> FindMinMaxX(int *colors, int color, int x, int y, int width, int height, int max_width, int max_height)
    {
        int min_x = -1;
        int max_x = -1;
        for (int i = 0; i < height; i++)
        {
            int iy = i + y;
            if (iy < 0 || iy >= max_height) continue;
            for (int j = 0; j < width; j++)
            {
                int jx = j + x;
                if (jx < 0 || jx >= max_width) continue;
                int index = iy * max_width + jx;
                if (colors[index] == color)
                {
                    if (min_x < 0 || jx < min_x)
                    {
                        min_x = jx;
                    }
                    if (max_x < 0 || jx > max_x)
                    {
                        max_x = jx;
                    }
                }
            }
        }
        return std::make_pair(min_x, max_x);
    }

    // 找指定颜色离指定点最大的点
    static int FindMaxX(int *colors, int color, int x, int y, int max_width, int max_height, int *in_out_count, int max_count)
    {
        int max_x = -1;
        int count = in_out_count == nullptr ? 0 : *in_out_count;

        if (y >= max_height || y < 0) return max_x;

        while (x < max_width && count < max_count)
        {
            int index = y * max_width + x;
            if (colors[index] == color)
            {
                max_x = x;
                count++;
            }
            else
            {
                break;
            }
            x++;
        }
        if (in_out_count != nullptr) *in_out_count = count;
        return max_x;
    }

    // 找指定颜色离指定点最大的点
    static int FindMinX(int *colors, int color, int x, int y, int max_width, int max_height, int *in_out_count, int max_count)
    {
        int min_x = -1;
        int count = in_out_count == nullptr ? 0 : *in_out_count;

        if (y >= max_height || y < 0) return min_x;

        while (x >= 0 && count < max_count)
        {
            int index = y * max_width + x;
            if (colors[index] == color)
            {
                min_x = x;
            }
            else
            {
                break;
            }
            x--;
        }
        if (in_out_count != nullptr) *in_out_count = count;
        return min_x;
    }

    // 找指定颜色离指定点最近的点
    static int FindNearestX(int *colors, int color, int x, int y, int max_width, int max_height)
    {
        int ix = -1;
        int i  = 0;

        if (y >= max_height || y < 0) return ix;

        while (i < max_width)
        {
            int right_index = y * max_width + x + i;
            if ((x + i) < max_width && colors[right_index] == color)
            {
                ix = x + i;
                break;
            }
            int left_index = y * max_width + x - i;
            if ((x - i) >= 0 && colors[left_index] == color)
            {
                ix = x - i;
                break;
            }
            if (left_index < 0 && right_index >= max_width) break;
            i++;
        }
        return ix;
    }

    // 在指定的区域里填充指定颜色
    static void FillColors(int *colors, int color, int x, int y, int width, int height, int max_width, int max_height)
    {
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int ix = i + x;
                int jy = j + y;
                if (ix < 0 || ix >= max_width || jy < 0 || jy >= max_height) continue;
                int index     = jy * max_width + ix;
                colors[index] = color;
            }
        }
    }

    // 获取指定区域里指定颜色数量
    static int GetColorCount(int *colors, int color, int x, int y, int width, int height, int max_width, int max_height)
    {
        int count = 0;
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int ix = i + x;
                int jy = j + y;
                if (ix < 0 || ix >= max_width || jy < 0 || jy >= max_height) continue;
                int index = jy * max_width + ix;
                if (colors[index] == color)
                {
                    count++;
                }
            }
        }
        return count;
    }

    // 获取指定区域里指定颜色中心
    static std::pair<float, float> GetColorCenter(int *colors, int color, int x, int y, int width, int height, int max_width, int max_height)
    {
        int avg_x    = 0;
        int avg_y    = 0;
        int avg_size = 0;
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int ix = i + x;
                int jy = j + y;
                if (ix < 0 || ix >= max_width || jy < 0 || jy >= max_height) continue;
                int index = jy * max_width + ix;
                if (colors[index] == color)
                {
                    avg_x += ix;
                    avg_y += jy;
                    avg_size++;
                }
            }
        }
        if (avg_size > 0)
        {
            return std::make_pair(avg_x * 1.0f / avg_size, avg_y * 1.0f / avg_size);
        }
        else
        {
            return std::make_pair(-1.f, -1.f);
        }
    }

    static void DebugGray(unsigned char *pixels, int max_width, int max_height, int x, int y, int width, int height)
    {
        std::cout << "debug gray => " << "x = " << x << ", y = " << y << ", width = " << width << ", height = " << height << std::endl;
        for (int j = 0; j < height; j++)
        {
            for (int i = 0; i < width; i++)
            {
                int ix    = i + x;
                int jy    = j + y;
                int index = (jy * max_width + ix) * 3;
                int r     = pixels[index];
                int g     = pixels[index + 1];
                int b     = pixels[index + 2];
                // int color = (r << 16) | (g << 8) | b;
                int gray = r * 0.299f + g * 0.587f + b * 0.114f;
                std::cout << std::setw(4) << gray;
            }
            std::cout << std::endl;
        }
        std::cout << std::endl;
    }

    static std::vector<int> MaxPool(int *pixels, int width, int height, int scale_width, int scale_height)
    {
        int scale_size = scale_width * scale_height;
        std::vector<int> scale_pixels(scale_size, 0);
        int step_x    = width / scale_width;
        int step_y    = height / scale_height;
        int step_size = step_x * step_y;

        for (int sy = 0; sy < scale_height; sy++)
        {
            for (int sx = 0; sx < scale_width; sx++)
            {
                int x   = sx * step_x;
                int y   = sy * step_y;
                int max = 0;
                for (int j = 0; j < step_y; j++)
                {
                    for (int i = 0; i < step_x; i++)
                    {
                        int index = (y + j) * width + x + i;
                        int value = pixels[index];
                        max       = value > max ? value : max;
                    }
                }
                scale_pixels[sy * scale_width + sx] = max;
                std::cout << std::setw(4) << max;
            }
            std::cout << std::endl;
        }
        std::cout << std::endl;

        return std::move(scale_pixels);
    }

    static std::vector<int> AvgPool(int *pixels, int width, int height, int scale_width, int scale_height)
    {
        int scale_size = scale_width * scale_height;
        std::vector<int> scale_pixels(scale_size, 0);
        int step_x    = width / scale_width;
        int step_y    = height / scale_height;
        int step_size = step_x * step_y;
        std::vector<int> step_pixels(step_size, 0);

        for (int sy = 0; sy < scale_height; sy++)
        {
            for (int sx = 0; sx < scale_width; sx++)
            {
                int x   = sx * step_x;
                int y   = sy * step_y;
                int sum = 0;
                for (int j = 0; j < step_y; j++)
                {
                    for (int i = 0; i < step_x; i++)
                    {
                        int index                   = (y + j) * width + x + i;
                        int value                   = pixels[index];
                        step_pixels[j * step_x + i] = value;
                        sum += value;
                    }
                }

                int avg          = sum / step_size;
                int avg_gt_sum   = 0;
                int avg_gt_count = 0;
                int avg_lt_sum   = 0;
                int avg_lt_count = 0;
                for (int i = 0; i < step_size; i++)
                {
                    if (step_pixels[i] >= avg)
                    {
                        avg_gt_sum += step_pixels[i];
                        avg_gt_count++;
                    }
                    else
                    {
                        avg_lt_sum += step_pixels[i];
                        avg_lt_count++;
                    }
                }
                avg                                 = (avg_gt_count > avg_lt_count ? (avg_gt_sum / avg_gt_count) : (avg_lt_sum / avg_lt_count));
                scale_pixels[sy * scale_width + sx] = avg;
                std::cout << std::setw(4) << avg;
            }
            std::cout << std::endl;
        }
        std::cout << std::endl;

        return std::move(scale_pixels);
    }

    static std::vector<int> ScaleGray(unsigned char *pixels, int width, int height, int scale_width, int scale_height)
    {
        int scale_size = scale_width * scale_height;
        std::vector<int> scale_pixels(scale_size, 0);
        int step_x    = width / scale_width;
        int step_y    = height / scale_height;
        int step_size = step_x * step_y;
        std::vector<int> step_pixels(step_size, 0);
        int max = 0;
        int min = 0xff * step_x * step_y;

        // DebugGray(pixels, width, height, 12 * step_x, 23 * step_y, step_x, step_y);
        // DebugGray(pixels, width, height, 30 * step_x, 23 * step_y, step_x, step_y);
        for (int sy = 0; sy < scale_height; sy++)
        {
            int scale_line_index = sy * scale_width;
            for (int sx = 0; sx < scale_width; sx++)
            {
                int x   = sx * step_x;
                int y   = sy * step_y;
                int sum = 0;
                for (int j = 0; j < step_y; j++)
                {
                    for (int i = 0; i < step_x; i++)
                    {
                        int index                   = ((y + j) * width + (x + i)) * 3;
                        int r                       = pixels[index];
                        int g                       = pixels[index + 1];
                        int b                       = pixels[index + 2];
                        int gray                    = r * 0.299f + g * 0.587f + b * 0.114f; // Gray = R * 0.299 + G * 0.587 + B * 0.114
                        step_pixels[j * step_x + i] = gray;
                        sum += gray;
                    }
                }

                // 将区域点按均值划分, 取点多那部分数据的均值作为整体均值, 边界处理, 忽略边界可不执行此计算
                int avg          = sum / step_size;
                int avg_gt_sum   = 0;
                int avg_gt_count = 0;
                int avg_lt_sum   = 0;
                int avg_lt_count = 0;
                for (int i = 0; i < step_size; i++)
                {
                    if (step_pixels[i] >= avg)
                    {
                        avg_gt_sum += step_pixels[i];
                        avg_gt_count++;
                    }
                    else
                    {
                        avg_lt_sum += step_pixels[i];
                        avg_lt_count++;
                    }
                }
                avg = avg_gt_count > avg_lt_count ? avg_gt_sum / avg_gt_count : avg_lt_sum / avg_lt_count;

                scale_pixels[scale_line_index + sx] = avg;
                min                                 = min < avg ? min : avg;
                max                                 = max > avg ? max : avg;
            }
        }

        for (int i = 0; i < scale_size; i++)
        {
            scale_pixels[i] = (scale_pixels[i] - min) * 0xff / (max - min);
        }

        for (int i = 0; i < scale_height; i++)
        {
            for (int j = 0; j < scale_width; j++)
            {
                int index = i * scale_width + j;
                std::cout << std::setw(4) << scale_pixels[index];
            }
            std::cout << std::endl;
        }

        // MaxPool(scale_pixels.data(), scale_width, scale_height, scale_width / 8, scale_height / 8); // 32 * 24 => 8 * 6
        // AvgPool(scale_pixels.data(), scale_width, scale_height, scale_width / 8, scale_height / 8); // 32 * 24 => 8 * 6
        auto tmp = AvgPool(scale_pixels.data(), scale_width, scale_height, scale_width / 4, scale_height / 4); // 32 * 24 => 8 * 6
        AvgPool(tmp.data(), scale_width / 4, scale_height / 4, scale_width / 8, scale_height / 8);             // 32 * 24 => 8 * 6
        return std::move(scale_pixels);
    }

    static inline bool IsRedColor(int r, int g, int b) { return (r - g) > 0x20 && (r - b) > 0x20 && (g < b ? b - g : g - b) < 0x18; }
    static int *GetRedRect(unsigned char *pixels, int width, int height, float scale = 0.2f)
    {
        std::vector<int> xs;
        std::vector<int> ys;

        int scale_width  = width * scale;
        int scale_height = height * scale;
        int scale_size   = scale_width * scale_height;
        std::vector<int> scale_pixels(scale_size, 0);
        int step_x    = width / scale_width;
        int step_y    = height / scale_height;
        int step_size = step_x * step_y;
        for (int sy = 0; sy < scale_height; sy++)
        {
            for (int sx = 0; sx < scale_width; sx++)
            {
                int x   = sx * step_x;
                int y   = sy * step_y;
                int sum = 0;
                for (int j = 0; j < step_y; j++)
                {
                    for (int i = 0; i < step_x; i++)
                    {
                        int index = ((y + j) * width + (x + i)) * 3;
                        int r     = pixels[index];
                        int g     = pixels[index + 1];
                        int b     = pixels[index + 2];
                        if (IsRedColor(r, g, b)) sum++;
                    }
                }
                if (sum >= (step_size / 2))
                {
                    scale_pixels[sy * scale_width + sx] = 1;
                    xs.push_back(sx);
                    ys.push_back(sy);
                }
                else
                {
                    scale_pixels[sy * scale_width + sx] = 0;
                }
            }
        }

        int size = xs.size();
        if (size == 0) return nullptr;

        auto avg_width  = 0;
        auto avg_height = 0;
        std::vector<int> x_dists(size, 0);
        std::vector<int> y_dists(size, 0);
        for (int i = 0; i < size; i++)
        {
            auto max_width  = 0;
            auto max_height = 0;
            for (int j = i + 1; j < size; j++)
            {
                max_width  = std::max(max_width, std::abs(xs[i] - xs[j]));
                max_height = std::max(max_height, std::abs(ys[i] - ys[j]));
            }
            avg_width += max_width;
            avg_height += max_height;
            x_dists.push_back(max_width);
            y_dists.push_back(max_height);
        }
        avg_width  = avg_width / size * 2;
        avg_height = avg_height / size * 2;

        auto min_x      = scale_width;
        auto min_y      = scale_height;
        auto max_x      = 0;
        auto max_y      = 0;
        auto valid_size = 0;
        for (int i = 0; i < size; i++)
        {
            auto x      = xs[i];
            auto y      = ys[i];
            auto x_dist = x_dists[i];
            auto y_dist = y_dists[i];
            if (x_dist > avg_width || y_dist > avg_height) continue;
            min_x = min_x < x ? min_x : x;
            min_y = min_y < y ? min_y : y;
            max_x = max_x < x ? x : max_x;
            max_y = max_y < y ? y : max_y;
            valid_size++;
        }
        if (min_x > max_x || min_y > max_y) return nullptr;

        int extend_size         = 20;
        int rect_x              = min_x / scale - extend_size / 2;
        int rect_y              = min_y / scale - extend_size / 2;
        int rect_width          = (max_x - min_x) / scale + extend_size;
        int rect_height         = (max_y - min_y) / scale + extend_size;
        static int s_results[4] = {0, 0, 0, 0};
        s_results[0]            = rect_x < 0 ? 0 : rect_x;
        s_results[1]            = rect_y < 0 ? 0 : rect_y;
        s_results[2]            = rect_width > width ? width : rect_width;
        s_results[3]            = rect_height > height ? height : rect_height;
        return s_results;
    }

    static std::string GetRedRectDatas(unsigned char *pixels, int width, int height, float scale, int fixed_width, int fixed_height)
    {
        auto rects = GetRedRect(pixels, width, height, scale);
        if (rects == nullptr) return "";
        auto x = rects[0];
        auto y = rects[1];
        auto w = rects[2];
        auto h = rects[3];

        // 取目标图像
        std::vector<unsigned char> rect_pixels(w * h * 3);
        for (int j = 0; j < h; j++)
        {
            for (int i = 0; i < w; i++)
            {
                auto ix        = x + i;
                auto jy        = y + j;
                auto dst_index = (j * w + i) * 3;
                auto src_index = (jy * width + ix) * 3;
                if (ix < 0 || ix >= width || jy < 0 || jy >= height)
                {
                    rect_pixels[dst_index + 0] = 0;
                    rect_pixels[dst_index + 1] = 0;
                    rect_pixels[dst_index + 2] = 0;
                }
                else
                {
                    rect_pixels[dst_index + 0] = pixels[src_index + 0];
                    rect_pixels[dst_index + 1] = pixels[src_index + 1];
                    rect_pixels[dst_index + 2] = pixels[src_index + 2];
                }
            }
        }

        // stbi_write_jpg("d:/test.jpg", w, h, 3, rect_pixels.data(), w);

        // 缩放到指定大小
        std::vector<unsigned char> dst_pixels(fixed_width * fixed_height * 3);
        float scale_x   = fixed_width * 1.0f / w;
        float scale_y   = fixed_height * 1.0f / h;
        float min_scale = scale_x < scale_y ? scale_x : scale_y;
        int offset_x    = (fixed_width / min_scale - w) / 2;
        int offset_y    = (fixed_height / min_scale - h) / 2;
        for (int j = 0; j < fixed_height; j++)
        {
            for (int i = 0; i < fixed_width; i++)
            {
                int ix         = i / min_scale - offset_x;
                int jy         = j / min_scale - offset_y;
                auto dst_index = (j * fixed_width + i) * 3;
                auto src_index = (jy * w + ix) * 3;
                if (ix < 0 || ix >= w || jy < 0 || jy >= h)
                {
                    dst_pixels[dst_index + 0] = 0;
                    dst_pixels[dst_index + 1] = 0;
                    dst_pixels[dst_index + 2] = 0;
                }
                else
                {
                    dst_pixels[dst_index + 0] = rect_pixels[src_index + 0];
                    dst_pixels[dst_index + 1] = rect_pixels[src_index + 1];
                    dst_pixels[dst_index + 2] = rect_pixels[src_index + 2];
                }
            }
        }
        // stbi_write_jpg("d:/test1.jpg", fixed_width, fixed_height, 3, dst_pixels.data(), fixed_width);
        std::ostringstream oss;
        for (int y = 0; y < fixed_height; y++)
        {
            for (int x = 0; x < fixed_width; x++)
            {
                int index = (y * fixed_width + x) * 3;
                oss << std::to_string(dst_pixels[index]) << " " << std::to_string(dst_pixels[index + 1]) << " " << std::to_string(dst_pixels[index + 2]) << " ";
            }
            oss << std::endl;
        }
        return oss.str();
    }
};

#endif